home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_11_03 / 1103028a < prev    next >
Text File  |  1992-11-14  |  21KB  |  948 lines

  1. /****************************************************/
  2. /*                                                  */
  3. /*      SSX.C - stack swap executive                */
  4. /*                                                  */
  5. /*      By Tom Green and Dennis Cronin              */
  6. /*      10/19/92                                    */
  7. /*                                                  */
  8. /****************************************************/
  9.  
  10. /* turn on inline asm */
  11. #pragma inline
  12.  
  13. #include <alloc.h>
  14. #include <dos.h>
  15. #include <string.h>
  16. #include <setjmp.h>
  17. #include "ssx.h"
  18. #include "ssx_conf.h"
  19.  
  20. /*  Task Control Block */
  21.  
  22. typedef struct tcb {
  23.     /* task chain forward ptr */
  24.     struct tcb *forw;
  25.     /* task chain backward ptr */
  26.     struct tcb *back;
  27.     /* delay chain forward ptr */
  28.     struct tcb *dforw;
  29.     /* delay chain backward ptr */
  30.     struct tcb *dback;
  31.     /* pointer to task code */
  32.     fptr task_ptr;
  33.     /* pointer to start of allocated stack */
  34.     unsigned int *stack;
  35.     /* task's current stack pointer */
  36.     unsigned int *stack_ptr;
  37.     /* delay counter */
  38.     long timeout;
  39.     /* flag for task timed out */
  40.     unsigned char timedout;
  41.     /* flag for TCB in use */
  42.     unsigned char active;
  43.     /* status flags */
  44.     unsigned char status;
  45.     /* task priority */
  46.     unsigned char priority;
  47.     /* task ID */
  48.     unsigned char id;
  49.     /* for storing extra task context */
  50.     char context[CNTXT_SZ];
  51. } tcb;
  52.  
  53.  
  54. /* misc. defines */
  55. #define TRUE            1
  56. #define FALSE           0
  57.  
  58. /* background task defines */
  59. #define BG_TASK_ID      0xff
  60. #define BG_TASK_PRI     0xff
  61.  
  62. /*  make data and code local to this file */
  63. #define LOCAL static
  64.  
  65. /* flags for the TCB status word */
  66. #define T_READY         0    /* ready to run */
  67. #define T_WAITING       1    /* waiting on wait_q */
  68. #define T_DELAYED       2    /* delay timer running */
  69.  
  70.  
  71. /* local function prototypes */
  72.  
  73. LOCAL tcb *get_tcb(void);
  74. LOCAL void free_tcb(tcb *tbp);
  75. LOCAL void put_ready(tcb *tbp);
  76. LOCAL void rotate_tasks(tcb *tbp);
  77. LOCAL void put_delay(long timeout);
  78. LOCAL void run_new_task(void);
  79. LOCAL void bg_task(void);
  80. LOCAL void stack_swap(unsigned int **old_stack_ptr,
  81.                         unsigned int **new_stack_ptr);
  82. LOCAL int disable_ints(void);
  83.  
  84.  
  85. /*  local variables  */
  86.  
  87. LOCAL long sys_time;                /* system timer */
  88. LOCAL unsigned char slice_cnt;
  89. LOCAL int running;
  90. LOCAL int initd;
  91. LOCAL jmp_buf jbuf;
  92. LOCAL int switch_lock;
  93.  
  94. /* task control */
  95. LOCAL tcb t_pool[MAX_TASKS + 1]; /* pool of TCBs */
  96. LOCAL tcb t_ready;    /* head of ready task queue */
  97. LOCAL tcb t_null;     /* the NULL task */
  98. LOCAL tcb *t_free;    /* head of free queue */
  99. LOCAL tcb *t_current; /* pointer to current task */
  100.  
  101. /* delay control */
  102. LOCAL tcb d_chain;    /* q head for delayed tasks */
  103.  
  104. /* MACROS to unlink from task and delay queues */
  105.  
  106. /* t_unlink - must be used w/ interrupts off */
  107. #define     t_unlink(tbp)                           \
  108.      {                                              \
  109.         (tbp)->back->forw = (tbp)->forw;            \
  110.         if((tbp)->forw != NULL)                     \
  111.             (tbp)->forw->back = (tbp)->back;        \
  112.     }
  113.  
  114. /* d_unlink - must be used w/ interrupts off */
  115. #define     d_unlink(tbp)                           \
  116.     {                                               \
  117.         (tbp)->dback->dforw = (tbp)->dforw;         \
  118.         if((tbp)->dforw != NULL)                    \
  119.             (tbp)->dforw->dback = (tbp)->dback;     \
  120.     }
  121.  
  122.  
  123. /*
  124.  * ssx_init - init ssx data
  125.  */
  126.  
  127. int
  128. ssx_init(void)
  129. {
  130.     int i;
  131.     tcb *tcbp;
  132.  
  133.     if(initd)
  134.         return(INIT_ERROR);
  135.  
  136.     memset(&d_chain,0,sizeof(d_chain));
  137.  
  138.     /* init TCB free queue links */
  139.     for(i=0,tcbp=t_pool;i < MAX_TASKS-1;i++,tcbp++){
  140.         tcbp->forw = &t_pool[i+1];
  141.     }
  142.     t_pool[i].forw = NULL;
  143.  
  144.     for(i = 0;i < MAX_TASKS;i++){
  145.         t_pool[i].active=FALSE;
  146.     }
  147.  
  148.     t_current = NULL;
  149.     t_free = t_pool;
  150.     t_ready.forw = NULL;
  151.     switch_lock = 0;
  152.  
  153.     /* set up background task */
  154.     if((ssx_task_create(BG_TASK_PRI,BG_TASK_ID,
  155.                         bg_task,0x200,"bg_task"))
  156.                         != SUCCESS)
  157.         return(INIT_ERROR);
  158.  
  159.     initd = TRUE;
  160.  
  161.     return(SUCCESS);
  162. }
  163.  
  164.  
  165. /*
  166.  * sx_run - this starts executive
  167.  */
  168.  
  169. void
  170. ssx_run(void)
  171. {
  172.     int val;
  173.  
  174.     val = setjmp(jbuf);
  175.     
  176.     if(val != 0)
  177.         return;
  178.  
  179.     slice_cnt = 0;
  180.     sys_time = 0;
  181.  
  182.     /* make current task ptr point to dummy tcb so
  183.      * beginning of time stack pointer save will
  184.      * have a safe place to save to.
  185.      */
  186.  
  187.     t_current = &t_null;
  188.  
  189.     /* mark SSX as active */
  190.     running = TRUE;
  191.     
  192.     /* this will start the first task rolling */
  193.     ssx_switch();
  194. }
  195.  
  196. /*
  197.  * sx_stop - this stops executive
  198.  */
  199.  
  200. void
  201. ssx_stop(void)
  202. {
  203.     int i;
  204.     int_state_var istate;
  205.  
  206.     ints_off(istate);
  207.  
  208.     /* free any allocated stacks */
  209.     for(i = 0; i < MAX_TASKS; i++){
  210.         if(t_pool[i].stack != NULL){
  211.             free(t_pool[i].stack);
  212.             t_pool[i].stack = NULL;
  213.         }
  214.     }
  215.     initd = FALSE;
  216.     running = FALSE;
  217.     restore_ints(istate);
  218.  
  219.     longjmp(jbuf,1);
  220. }
  221.  
  222.  
  223. /*
  224.  * ssx_task_create - create task and set up tcb
  225.  */
  226.  
  227. int
  228. ssx_task_create(unsigned char task_pri,
  229.                 unsigned char task_id,fptr task_ptr,
  230.                 unsigned int stack_size,char *name)
  231. {
  232.     unsigned int i;
  233.     tcb *tbp;
  234.     int_state_var istate;
  235.  
  236.     ints_off(istate);
  237.  
  238.     if(task_id == 0) {
  239.         restore_ints(istate);
  240.         return(TID_ERR);
  241.     }
  242.  
  243.     /* check for TID already in use */
  244.     for(i = 0,tbp = t_pool;i < MAX_TASKS;i++,tbp++) {
  245.         if(tbp->active && tbp->id == task_id) {
  246.             restore_ints(istate);
  247.             return(TID_ERR);
  248.         }
  249.     }
  250.  
  251.     if((tbp = get_tcb()) == NULL) {    /* get a tcb */
  252.         restore_ints(istate);
  253.         return(TCB_ERR);
  254.     }
  255.  
  256.  
  257.     /* allocate stack for this task */
  258.     if((tbp->stack = (unsigned int *)
  259.                       malloc(stack_size)) == NULL){
  260.         restore_ints(istate);
  261.         return(STACK_ERR);
  262.     }
  263.  
  264.     /* fill in the blanks */
  265.     strncpy(tbp->context,name,CNTXT_SZ);
  266.     tbp->priority = task_pri;
  267.     tbp->id = task_id;
  268.     tbp->status = T_READY;
  269.     tbp->timedout = FALSE;
  270.     tbp->timeout = 0L;
  271.     tbp->forw = tbp->back =
  272.     tbp->dforw = tbp->dback = NULL;
  273.  
  274.     tbp->task_ptr = task_ptr;
  275.  
  276.     tbp->stack_ptr = (unsigned int *)(tbp->stack +
  277.                      (stack_size / 2));
  278.  
  279.     /* setup task stack to have address of start up
  280.      * routine and fake di, si, bp registers to pop.
  281.      * This part is not portable. the stack looks 
  282.      * like this:
  283.      *
  284.      *  |-------------------------|         high
  285.      *  |address of run_new_task  |
  286.      *  |-------------------------|
  287.      *  |bp                       |
  288.      *  |-------------------------|
  289.      *  |si                       |
  290.      *  |-------------------------|
  291.      *  |di                       |
  292.      *  |-------------------------|         low
  293.      *
  294.      */
  295.  
  296.     *(--tbp->stack_ptr) = (unsigned int)run_new_task;
  297.     *(--tbp->stack_ptr) = 0;     /* fake BP,SI,DI */
  298.     *(--tbp->stack_ptr) = 0;     /* on stack */
  299.     *(--tbp->stack_ptr) = 0;
  300.  
  301.     /* put on active chain */
  302.     rotate_tasks(tbp);
  303.  
  304.     ssx_switch();
  305.  
  306.     restore_ints(istate);
  307.  
  308.     return(SUCCESS);
  309. }
  310.  
  311.  
  312. /*
  313.  * ssx_task_delay - cause task to delay for number
  314.  *                  of ticks
  315.  */
  316.  
  317. void
  318. ssx_task_delay(long timeout)
  319. {
  320.     int_state_var istate;
  321.     
  322.     ints_off(istate);
  323.  
  324.     if(timeout == 0) {
  325.         ssx_switch();
  326.         restore_ints(istate);
  327.         return;
  328.     }
  329.  
  330.     put_delay(timeout);  /* put current task on */
  331.                          /* delay queue */
  332.     t_unlink(t_current); /* take off ready queue */
  333.  
  334.     ssx_switch();
  335.     restore_ints(istate);
  336. }
  337.  
  338.  
  339. /*
  340.  * ssx_task_delete - delete a task and remove from
  341.  *                   queues
  342.  */
  343.  
  344. int
  345. ssx_task_delete(unsigned char tas